home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / timidsrc.zip / dart_a.c < prev    next >
C/C++ Source or Header  |  1997-04-26  |  8KB  |  266 lines

  1. /*
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
  5.  
  6.      This program is free software; you can redistribute it and/or modify
  7.      it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.      (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.      GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     dart_c.c: This is the output driver for OS/2 DART output. 
  21. */
  22. #define INCL_DOSSEMAPHORES
  23. #define INCL_DOSPROCESS
  24. #define INCL_NOPMAPI
  25. #define INCL_MCIOS2
  26.  
  27. #include <os2.h>
  28. #include <os2me.h>
  29.  
  30. #include "config.h"
  31. #include "output.h"
  32. #include "controls.h"
  33. #include "tables.h"
  34.  
  35. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  36. static void close_output(void);
  37. static void output_data(int32 *buf, int32 count);
  38. static void flush_output(void);
  39. static void purge_output(void);
  40.  
  41. /* export the playback mode */
  42. #define dpm dart_play_mode
  43.  
  44. PlayMode dpm = {
  45.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  46.   -1,
  47.   {40/*buffers*/,1/*dynamic priority*/,0,0,0},
  48.   "OS/2 DART output", 'd',
  49.   "",
  50.   open_output,
  51.   close_output,
  52.   output_data,
  53.   flush_output,
  54.   purge_output
  55. };
  56.  
  57. #define PRIORTY_DELTA 30
  58. int max_buffers,
  59.     gohigh,
  60.     offhigh;
  61. #ifdef PM
  62. extern HEV pausesem;
  63. extern int paused;
  64. extern unsigned int currtime;
  65. extern int timeoffset;
  66. extern HWND Frame;
  67. #endif
  68. LONG MyEvent (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags);
  69. MCI_MIX_BUFFER Buffers[100];
  70. MCI_MIXSETUP_PARMS MixSetupParms = {NULLHANDLE,0,MCI_WAVE_FORMAT_PCM,0,0,MCI_PLAY,MCI_DEVTYPE_WAVEFORM_AUDIO,0,NULL,NULL,MyEvent,NULL,0,0};
  71. MCI_AMP_OPEN_PARMS AmpOpenParms = {NULLHANDLE,0,0,(PSZ)MCI_DEVTYPE_AUDIO_AMPMIX,NULL,NULL,NULL};
  72. MCI_BUFFER_PARMS BufferParms = {NULLHANDLE,sizeof(MCI_BUFFER_PARMS),0,
  73.                 1 << (AUDIO_BUFFER_BITS),0,0,0,Buffers};
  74. int buffcount=0,
  75.     numout=0,
  76.     blocking=0,
  77.     flushing=0,
  78.     hipri=0;
  79. HEV sem;
  80. ULONG threadID;
  81.  
  82. void s32copytos16(int32 *lp, int32 c, int16 *sp)
  83. {
  84.   int32 l;
  85.   while (c--)
  86.     {
  87.       l=(*lp++)>>(32-16-GUARD_BITS);
  88.       if (l > 32767) l=32767;
  89.       else if (l<-32768) l=-32768;
  90.       *sp++ = (int16)(l);
  91.     }
  92. }
  93.  
  94. void s32copytou8(int32 *lp, int32 c, uint8 *cp)
  95. {
  96.   int32 l;
  97.   while (c--)
  98.     {
  99.       l=(*lp++)>>(32-8-GUARD_BITS);
  100.       if (l>127) l=127;
  101.       else if (l<-128) l=-128;
  102.       *cp++ = 0x80 ^ ((uint8) l);
  103.     }
  104. }
  105.  
  106. void s32copytoulaw(int32 *lp, int32 c, uint8 *up)
  107. {
  108.   int32 l;
  109.   while (c--)
  110.     {
  111.       l=(*lp++)>>(32-13-GUARD_BITS);
  112.       if (l > 4095) l=4095;
  113.       else if (l<-4096) l=-4096;
  114.       *up++ = _l2u[l];
  115.     }
  116. }
  117.  
  118. LONG MyEvent (ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags) {
  119.    if (ulFlags & MIX_STREAM_ERROR && ulStatus==ERROR_DEVICE_UNDERRUN) {
  120.       if (!hipri && !flushing && dpm.extra_param[1]) {
  121.      hipri=1;
  122.      DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,PRIORTY_DELTA,threadID);
  123.       }
  124.       if (flushing) {
  125.      DosPostEventSem(sem);
  126.      blocking=0;
  127.       }
  128.    }
  129.    if (ulFlags & MIX_WRITE_COMPLETE) {
  130. #ifdef PM      
  131.       /*      currtime=pBuffer->ulTime+timeoffset;*/
  132.       currtime+=pBuffer->ulBufferLength;
  133. #endif      
  134.       numout--;
  135.       if (numout<gohigh && !hipri && !flushing && dpm.extra_param[1]) {
  136.          hipri=1;
  137.      DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,PRIORTY_DELTA,threadID);
  138.       }
  139.       if (blocking || (flushing && !numout)) {
  140.          DosPostEventSem(sem);
  141.          blocking=0;
  142.       }
  143.    }
  144.    return 0;
  145. }
  146.  
  147. void error(ULONG rc) {
  148.    char errstr[80];
  149.  
  150.    mciGetErrorString(rc,errstr,80);
  151.    ctl->cmsg(CMSG_ERROR,VERB_NORMAL,"MMOS/2 error: %s",errstr);
  152. }
  153.  
  154. PTIB ptib=NULL;
  155.  
  156. static int open_output(void) {
  157.    ULONG rc;
  158.    PPIB ppib=NULL;
  159.  
  160. #ifdef PM   
  161.    AmpOpenParms.hwndCallback=Frame;
  162. #endif
  163.    rc = mciSendCommand(0,MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID
  164. #ifdef PM            
  165.                | MCI_OPEN_SHAREABLE
  166. #endif            
  167.                ,&AmpOpenParms,0);
  168.    if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
  169.    /* They can't mean these */
  170.    dpm.encoding&=~PE_BYTESWAP;
  171.    dpm.encoding&=~PE_ULAW;
  172.    if (dpm.encoding & PE_16BIT) dpm.encoding|=PE_SIGNED;
  173.    else dpm.encoding&=~PE_SIGNED;
  174.    MixSetupParms.ulBitsPerSample=dpm.encoding & PE_16BIT?16:8;
  175.    MixSetupParms.ulSamplesPerSec=dpm.rate;
  176.    MixSetupParms.ulChannels=dpm.encoding & PE_MONO?1:2;
  177.    rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_MIXSETUP,
  178.              MCI_WAIT | MCI_MIXSETUP_INIT,&MixSetupParms,0);
  179.    if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
  180.    if (!(dpm.encoding & PE_MONO)) BufferParms.ulBufferSize*=2;
  181.    if (dpm.encoding & PE_16BIT) BufferParms.ulBufferSize*=2;
  182.    max_buffers=dpm.extra_param[0];
  183.    BufferParms.ulNumBuffers=max_buffers;
  184.    if (max_buffers<10) dpm.extra_param[1]=0;
  185.    else {
  186.       gohigh=max_buffers/4;
  187.       offhigh=max_buffers/2;
  188.    }
  189.    rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_BUFFER,
  190.                      MCI_WAIT | MCI_ALLOCATE_MEMORY,&BufferParms,0);
  191.    if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
  192.    DosCreateEventSem(NULL,&sem,0,TRUE);
  193.    DosGetInfoBlocks(&ptib,&ppib);
  194.    threadID=ptib->tib_ptib2->tib2_ultid;
  195.    return 0;
  196. }
  197.  
  198. static void output_data(int32 *buf, int32 count) {
  199.    ULONG numposted;
  200.  
  201.    if (numout>=max_buffers) {
  202.       DosResetEventSem(sem,&numposted);
  203.       blocking=1;
  204.       DosWaitEventSem(sem,-1);
  205.    }
  206.    if (numout>offhigh && hipri) {
  207.       hipri=0;
  208.       DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
  209.    }
  210.    if (!(dpm.encoding & PE_MONO)) count*=2;
  211.    if (dpm.encoding & PE_16BIT) {
  212.       s32copytos16(buf,count,Buffers[buffcount].pBuffer);
  213.       count*=2;
  214.    } else {
  215.       if (dpm.encoding & PE_ULAW)
  216.      s32toulaw(buf,count);
  217.       else s32copytou8(buf,count,Buffers[buffcount].pBuffer);
  218.    }
  219.    Buffers[buffcount].ulBufferLength=count;
  220.    /*   Buffers[buffcount].ulUserParm=buffcount;*/
  221. #ifdef PM
  222.    if (paused) DosWaitEventSem(pausesem,-1); /*Doing a mixWrite when paused causes a resume*/
  223. #endif
  224.    MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle,&Buffers[buffcount++],1);
  225.    if (buffcount>=max_buffers) buffcount=0;
  226.    numout++;
  227. }
  228.  
  229. static void close_output(void) {
  230.    MCI_GENERIC_PARMS GenericParms;
  231.    ULONG rc;
  232.  
  233.    DosCloseEventSem(sem);
  234.    rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_BUFFER,
  235.                      MCI_WAIT | MCI_DEALLOCATE_MEMORY,&BufferParms,0);
  236.    if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
  237.    rc=mciSendCommand(AmpOpenParms.usDeviceID,MCI_CLOSE,MCI_WAIT,&GenericParms,0);
  238.    if (ULONG_LOWD(rc)!=MCIERR_SUCCESS) error(rc);
  239. }
  240.  
  241. static void flush_output(void) {
  242.    ULONG numposted;
  243.  
  244.    DosResetEventSem(sem,&numposted);
  245.    flushing=1;
  246.    if (!numout) DosPostEventSem(sem); /*Don't stop if already done*/
  247.    else
  248.       if (DosWaitEventSem(sem,6000)==640)
  249.          ctl->cmsg(CMSG_WARNING,VERB_NORMAL,"Output Flush timed out");
  250.    flushing=0;
  251.    if (hipri) {
  252.       hipri=0;
  253.       DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
  254.    }
  255. }
  256.  
  257. static void purge_output (void) {
  258.    MCI_GENERIC_PARMS GenericParms;
  259.  
  260.    mciSendCommand(AmpOpenParms.usDeviceID,MCI_STOP,MCI_WAIT,&GenericParms,0);
  261.    if (hipri) {
  262.       hipri=0;
  263.       DosSetPriority(PRTYS_THREAD,PRTYC_NOCHANGE,-PRIORTY_DELTA,threadID);
  264.    }
  265. }
  266.